package io.netty.util.internal;

import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.FastThreadLocal;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;

/**
 * Allow to retrieve the {@link EventExecutor} for the calling {@link Thread}.
 */
public final class ThreadExecutorMap {

    private static final FastThreadLocal<EventExecutor> mappings = new FastThreadLocal<>();

    private ThreadExecutorMap() {

    }

    public static EventExecutor currentExecutor() {
        return mappings.get();
    }

    private static void setCurrentEventExecutor(EventExecutor executor) {
        mappings.set(executor);
    }

    public static Executor apply(final Executor executor,final EventExecutor eventExecutor) {
        ObjectUtil.checkNotNull(executor,"executor");
        ObjectUtil.checkNotNull(eventExecutor,"eventExecutor");
        return command -> {
            executor.execute(apply(command,eventExecutor));
        };
    }

    public static Runnable apply(final Runnable command,final EventExecutor eventExecutor) {
        ObjectUtil.checkNotNull(command,"command");
        ObjectUtil.checkNotNull(eventExecutor,"eventExecutor");

        return () -> {
            setCurrentEventExecutor(eventExecutor);
            try {
                command.run();
            } finally {
                setCurrentEventExecutor(null);
            }
        };
    }

    public static ThreadFactory apply(final ThreadFactory threadFactory,final EventExecutor eventExecutor) {
        ObjectUtil.checkNotNull(threadFactory,"command");
        ObjectUtil.checkNotNull(eventExecutor,"eventExecutor");
        return r -> threadFactory.newThread(apply(r,eventExecutor));
    }
}
